home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / STDERRF.ZIP / STARTUP1.ASM < prev    next >
Assembly Source File  |  1995-05-29  |  12KB  |  424 lines

  1.     page 60,132
  2.     title Start_Up1 -- Intermediate Start Up Code for .EXE Programs
  3.     name Start_Up1
  4.  
  5. comment ÷
  6.     Start_Up1                        V1.05
  7. --------------------------------------------------------------------------
  8. NAME
  9.     startup1    Intermediate start up code for .exe programs
  10.  
  11. SYNOPSIS
  12.     extern Start_Up1
  13.     or
  14.     extern Start_Up1S
  15.  
  16.     See Programming Notes below for difference.
  17.  
  18. DESCRIPTION
  19.     This is the startup code for all .exe and .com assembly language
  20.     programs.  Just use the SYNOPSIS above in the main function to
  21.     include the startup code in the .exe file from a .lib.    For .com
  22.     assembly language programs, this source code must be the first
  23.     assembled so that this code is the linked first.
  24.  
  25.     This procedure parses the command line into argc and *argv[] similar
  26.     to C.  Argv[0] is the first command line argument not the program
  27.     name as in C.
  28.     
  29.     This procedure performs the following functions in addition to above
  30.     - Initializes the following global variables:
  31.       -- DGRP, segment address of DGROUP
  32.       -- STACK_BOTTOM, offset to stack bottom in DGROUP
  33.       -- PSP, segment address of PSP
  34.       -- ENVIRON, segment address of passed copy of the ENVIRONMENT
  35.       -- OSMAJOR, integer part of OS system
  36.       -- OSMINOR, decimal part of OS system
  37.     - If DOS version is less than 2.0, aborts with error message
  38.     - Initializes DS and ES segment registers to DGROUP
  39.     - Skrinks memory down to size of program by releasing all memory 
  40.       above program
  41.  
  42. RETURNS
  43.     If main returns to startup code.  The program terminiates with the 
  44.     return code in AL.
  45.  
  46. PROGRAMING NOTES
  47.     Assembled with Microsoft MASM V6.11A.
  48.  
  49.     Written to link with any memory model
  50.     
  51.     Assemble with the following command line options to get the desired
  52.     memory models:
  53.     
  54.     Command Line            Memory Model
  55.     /Dmemmod=tiny            Tiny (.com file)
  56.     /Dmemmod=small            Small (default)
  57.     /Dmemmod=compact        Compact
  58.     /Dmemmod=medium         Medium
  59.     /Dmemmod=large            Large
  60.     /Dmemmod=huge            Huge
  61.  
  62.     Written using the FORTRAN/PASCAL/BASIC calling convention so passed
  63.     parameters are pushed in the order of appearance in the proc 
  64.     declaration.
  65.  
  66.     This procedure can pass argc and argv on stack two ways.   The proc
  67.     declaration in the MAIN procedure will differ depending upon the 
  68.     choice.
  69.     
  70.     The default requires the following proc declaration:
  71.     
  72.         MAIN proc ARGC:word, ARGV:ptr
  73.     
  74.     If SIMPLE is defined, an alternate proc declaration is required:
  75.     
  76.         MAIN proc ARGV:ptr, ARGC:word
  77.     
  78.     Here, ARGV is not a pointer to an array of pointers but the location
  79.     of the 1st pointer.
  80.  
  81.     Procedures called:
  82.         Main
  83.     DOS Interrupts
  84.         Int 21h  9h - Display String
  85.         Int 21h 30h - Get Version Number
  86.         Int 21h 4ah - Set Memory Block Size
  87.         Int 21h 4ch - Terminate program with return code
  88.  
  89.     In Huge memory model, the pointers passed in ARGV are long pointer
  90.     vice huge pointers.
  91.  
  92. MEMORY REQUIREMENTS
  93.     (in bytes)     Tiny   Small   Medium   Compact    Large    Huge
  94.     Code:        211    215    217     218     220    220
  95.     Code (SIMPLE):    208    212    214     214     216    216
  96.     _Data:          0     0      0       0       0      0
  97.     Const:         14    14     14      14      14     14
  98.     _BBS:         10    10     10      10      10     10
  99.     Stack:          ?     ?      ?       ?       ?      ?
  100.  
  101.     The first code size is for SIMPLE not defined.    The Code (SIMPLE) is
  102.     for when SIMPLE is defined.
  103.  
  104.     Stack usage is determined by the size of and the number of arguments
  105.     in the command line.
  106.  
  107.  
  108. CAUTION
  109.     Startup1 defines a 512 byte stack.  This should be enough for programs
  110.     who make moderate use of the stack.  If automatic variables are used
  111.     extensively, more stack space should be defined in the main module.
  112.     
  113. AUTHOR
  114.     Raymond Moon - 7 Sep 87
  115.  
  116.     Copyright (c) 1987, 1988, 1994, 1995 - MoonWare
  117.     ALL RIGHTS RESERVED
  118.  
  119. VERSION
  120.     Version    - Date        - Remarks
  121.     1.00    -  7 Sep 87    - Original
  122.     1.01    - 13 Feb 88    - Updated to program name as argv[0]
  123.                 - This created Startup1 from Startup0
  124.     1.02    -  4 Jul 88    - Converted to MASM V5.1
  125.     1.03    -  9 Oct 88    - Added Stack_Bottom & ZZ_PRGM_TOP segment
  126.                   to determine end of data.
  127.     1.04    - 30 Oct 94    - Moved ZZ_PRGM_TOP segment position in file.
  128.                 - Removed increment in program size in paras
  129.                     as ZZ_PRGM_TOP is aligned on a para.
  130.     1.05    -  5 Mar 95    - Added TINY Model capability
  131.                 - Converted to .dosseg using __end vice
  132.                   ZZ_PRGM_TOP for end of data
  133.  
  134. ==========================================================================
  135.     ÷  Commend End
  136.  
  137. ;-----------------------------
  138. ;    Make the small memory model the default
  139.  
  140. ifndef    memmod
  141. memmod    equ    <small>
  142. endif
  143.  
  144.     include procesor.inc
  145. %    .MODEL    memmod,FORTRAN
  146.     assume    es:DGROUP
  147.     .dosseg
  148.  
  149. ;----------------------------
  150. ;    Required includes
  151.  
  152.     include stderrf.inc
  153.  
  154. ;----------------------------
  155. ;    Define any required equates
  156.  
  157. STACK_SIZE    equ    512
  158.  
  159. ;=========================================================================
  160. ;    DATA
  161. ;=========================================================================
  162. ;    Define storage for the various global and system variables and
  163. ;    constants.
  164.  
  165.     .CONST
  166.  
  167. BAD_DOS_VERSION    db    'Need DOS 2.0+$'
  168.  
  169.     .DATA?
  170.  
  171. DGRP        dw    ?    ; Value of DGROUP
  172. STACK_BOTTOM    dw    ?    ; Offset to stack bottom in DGROUP
  173. PSP        dw    ?    ; Segment address of PSP
  174. ENVIRON     dw    ?    ; Segment address of ENVIRON
  175. OSMAJOR     db    ?    ; Integer part of OS system
  176. OSMINOR     db    ?    ; Decimal part of OS system
  177.  
  178. if    @Model    NE  1
  179.     .STACK    STACK_SIZE    ; Define a nominal stack
  180. endif
  181.  
  182. @CurSeg ends
  183.  
  184. ;----------------------------
  185. ;    Define __end which is defined when using .dosseg
  186.  
  187. externdef    __end:byte
  188.  
  189.  
  190. ;----------------------------
  191. ;    Define segment for addressing information in the PSP
  192.  
  193. PSP_SEG    segment at 00h
  194.     
  195.     org    2ch
  196. ENVIRON_PTR    dw    ?        ; Segment address of Environment
  197.  
  198.     org     80h
  199. PARM_LEN     db    ?        ; Number of bytes in Command Line tail
  200. PARMS       db    127 dup(?)    ; Start of Command Line tail
  201. PSP_SEG    ends
  202.  
  203. ;=========================================================================
  204. ;    CODE
  205. ;=========================================================================
  206. ;    Put the called main procedure in the proper relationship to the
  207. ;    startup code.
  208.  
  209. if @CodeSize
  210. extrn    Main:far
  211. .CODE
  212. else
  213. .CODE
  214. extrn    Main:near
  215. endif
  216.  
  217. ;-----------------------------
  218. ;    Include org statement if tiny model
  219.  
  220. if    @Model    EQ 1
  221.  
  222.     org    100h
  223. endif
  224.  
  225. ;-----------------------------
  226. ;    Start the Start_Up1 code.  Make it a far procedure so error return
  227. ;    will work.  If SIMPLE is defined, redefined Start_Up1 as Start_Up1S.
  228.  
  229. ifdef SIMPLE
  230. Start_Up1    equ    <Start_Up1S>
  231. endif
  232.  
  233. % Start_Up1    proc    far
  234.  
  235. ;-----------------------------
  236. ;    First, initialize global variables.  Set DS to DGROUP.
  237.  
  238. if    @Model    NE 1
  239.     mov    ax, DGROUP        ; Get seg address of DGROUP
  240.     mov    ds, ax            ; Initialize DS segment register
  241.     mov    DGRP, ax        ; Initialize DGRP
  242. else
  243.     mov    DGRP, ds        ; Initialize DGRP
  244. endif
  245.  
  246.     mov    PSP, es            ; Initialize PSP
  247. assume    es:PSP_SEG
  248.     mov    bx, es:ENVIRON_PTR    ; Get segment address of environment
  249.     mov    ENVIRON, bx        ; Initialize ENVIRON
  250.     mov    ah, 30h            ; Get DOS version number
  251.     int    21h            ; Call DOS
  252.     mov    OSMAJOR, al        ; Save major version number
  253.     mov    OSMINOR, ah        ; Save minor version number
  254.     
  255. ;----------------------------
  256. ;    If DOS version is prior to 2.0, write error message and terminate
  257. ;    the program.  The program terminates with a far call to INT 20h.
  258.  
  259.     cmp    al, 2            ; Is the OS 2.0 below?
  260.     jae    SU1            ; No, continue
  261.     mov    ah, 9            ; DOS display string
  262.     lea    dx, BAD_DOS_VERSION    ; DS:DX => string to be displayed
  263.     int    21h            ; Call DOS
  264.     push    PSP            ; Push return segment
  265.     xor    ax, ax            ; AX = 0
  266.     push    ax            ; Push return IP
  267.     ret                ; Far return to PSP:0000
  268.  
  269. ;----------------------------
  270. ;    Combine the stack into DGROUP so that it is addressable from DGROUP.
  271. ;    Initialize STACK_BOTTOM.
  272.  
  273. SU1:    lea    bx, __end        ; Get pointer to end of data
  274.  
  275. if    @Model    eq    1        ; Ensure that Stack bottom at paragraph
  276.     and    bx, 0fff0h        ; Truncate to lower paragraph
  277.     add    bx, 16            ; Add one paragraph
  278. endif
  279.  
  280.     mov    STACK_BOTTOM, bx    ; Save it
  281.  
  282. if    @Model    eq    1        ; Get stack size
  283.     add    bx, STACK_SIZE        ; DI = stack size
  284. else
  285.     add    bx, sp            ; DI = stack size
  286. endif
  287.  
  288.     mov    dx, ds            ; Get DGROUP segment address
  289.     mov    ss, dx            ; Reset SS
  290.     mov    sp, bx            ; Reset SP
  291.  
  292. ;----------------------------
  293. ;    Release all memory above program.  Calculate the size of the program
  294. ;    in paragraphs (16 bits).  BX starts with Stack Top
  295.  
  296.     mov    cl, 4            ; Convert to #para by dividing by 16
  297.     shr    bx, cl            ; Do division by bit shifting
  298.  
  299. if    @Model    ne    1        ; Needed in non-Tiny memory models
  300.     mov    ax, ds            ; AX => DGROUP
  301.     sub    ax, PSP            ; AX = # para for code
  302.     add    bx, ax            ; BX = # para in program
  303. endif
  304.  
  305.     mov    ah, 4ah            ; Request DOS set block
  306.     int    21h            ; Call DOS
  307.  
  308. ;----------------------------
  309. ;    See if there are any command line arguments.  If not, all command
  310. ;    line processing is skipped.  The pushed null on the stack will be
  311. ;    argc, and a null pointer is also pushed onto the stack so argv[0]
  312. ;    is a null pointer.
  313.  
  314.     xor    dx,dx            ; Ensure DX is null
  315.     push    dx            ; Ensure null on top of stack
  316.     mov    bp,sp            ; BP = top of stack
  317.     cmp    es:PARM_LEN,0        ; Are there any Command Line arguments
  318.     jne    SU2            ; No, go process what is on the stack
  319.     push    dx            ; Push null pointer
  320. if @DataSize
  321.     push    dx            ; Make a doubleword null pointer
  322. endif
  323.     mov    es,DGRP            ; Initialize ES
  324.     jmp    short SU10        ; Go call MAIN
  325.  
  326. ;----------------------------
  327. ;    There are command line arguments.  Parse them onto the stack and 
  328. ;    build ARGC and ARGV.  Start this by transferring the entire command
  329. ;    line tail onto the stack.  Make room for them by moving SP.
  330.  
  331. SU2:    mov    cl, es:PARM_LEN        ; Get # of bytes in Command Line
  332.     inc    cx            ; increase by one
  333.     and    cx, 0feh        ; Force an even count
  334.     mov    ax, sp            ; Get SP
  335.     sub    ax, cx            ; Subtract PARM_LEN
  336.     mov    sp, ax            ; Reset SP, room on Stack
  337.     lea    si, es:PARMS        ; Load source addr in SI
  338.     mov    di, sp            ; Load destin addr in DI
  339.     mov    es, DGRP        ; ES => DGROUP
  340. assume    es:DGROUP
  341.     mov    ds, PSP            ; DS => PSP
  342.     rep    movsb            ; Move Command Line onto the Stack
  343.     mov    ds, es:DGRP        ; Restore DS
  344.     
  345. ;-----------------------------
  346. ;    Convert all blanks, not within double quotes, in the Command Line
  347. ;    to Nul.  CX is IN_LITERAL_FLAG.
  348.  
  349.     mov    bx, bp            ; BX points to last byte in stack
  350.     xor    cx, cx            ; Clear IN_LITERAL_FLAG
  351. SU3:    mov    al, [bx]        ; Get byte
  352.     cmp    al, '"'            ; Is it a literal?
  353.     jne    SU4            ; No, go to next test
  354.     inc    cx            ; Set IN_LITERAL_FLAG
  355.     and    cx, 1            ; Ensure only 0, & 1 valid
  356.     jmp    short SU5        ; Continue, and blank '"'
  357. SU4:    cmp    al, ' '            ; Is it a blank?
  358.     ja    SU6            ; No, go set up to get another
  359.     or    cx, cx            ; Is IN_LITERAL_FLAG clear?
  360.     jne    SU6            ; No, do not null blank
  361. SU5:    xor    al, al            ; Nul AX
  362.     mov    [bx], al        ; Store Nul in [BX]
  363. SU6:    dec    bx            ; BX point to next byte
  364.     cmp    bx, sp            ; Are we through yet?
  365.     jnb    SU3            ; No, go one mo' 'gin
  366.                     
  367. ;-----------------------------
  368. ;    Build *argv[].  argc kept in CX.  DX used as IN_WORD flag
  369. ;    Build it backwards.  CX is 0 upon entry.
  370.  
  371.     mov    dx, cx            ; Set CX (argc) to 0
  372.     push    cx            ; Put a null at the start
  373.     mov    bx, bp            ; BX point to last byte
  374.     mov    bp, sp            ; BP now points to Top of Stack
  375. SU7:    mov    al, [bx - 1]        ; Get byte
  376.     or    al, al            ; Is it Nul?
  377.     jnz    SU8            ; No, it is a char
  378.     or    dx, dx            ; Was the last byte not a char?
  379.     jz    SU9            ; Yes, go on with the processing
  380.     xor    dx, dx            ; No, it was a char.  Clear IN_WORD.
  381.     inc    cx            ; Increment argc
  382. if @DataSize
  383.     push    ss            ; Push segment address
  384. endif
  385.     push    bx            ; Push addr onto stack
  386.     jmp    short SU9        ; Go set up for another byte
  387. SU8:    inc    dx            ; Set DX to IN_WORD
  388. SU9:    dec    bx            ; BX point to next byte
  389.     cmp    bx, bp            ; Are we at the 1st byte yet?
  390.     jg    SU7            ; No, go process another
  391.  
  392. ;-----------------------------
  393. ;    Create argc and argv on the stack.  Default is FORTRAN calling
  394. ;    convention.  If SIMPLE is defined, push only argc.  See documentation
  395. ;    above for structure of proc declaration in MAIN procedure
  396.  
  397. ifndef SIMPLE
  398.     mov    bx, sp            ; BX = **argv[]
  399.     push    cx            ; Push argc
  400. if @DataSize
  401.     push    ss            ; Long pointer
  402. endif
  403.     push    bx            ; Push **argv[]
  404. else
  405.     push    cx            ; Push argc
  406. endif
  407.     
  408. ;-----------------------------
  409. ;    call MAIN
  410.  
  411. SU10:    call    Main            ; Call MAIN procedure
  412.  
  413. ;----------------------------
  414. ;    If main returns, the program is to terminate with the return code
  415. ;    returned in AL
  416.  
  417.     mov    ah, 4ch            ; End process
  418.     int    21h            ; Call DOS
  419.  
  420. % Start_Up1    endp
  421.  
  422. %    end    Start_Up1        ; Indicate that Start_Up1 is the start
  423.                     ; of the program
  424.